



import wx
import wx.grid as gridlib
import Npalace
import os


class SudokuApp(wx.App):
    """
    Define Application class.
    """
    
    def OnInit(self):
        self.title = 'Sudoku'
        frame = SudokuFrame("Sudoku", (0, 0), (400, 500))
        frame.Show(True)
        self.SetTopWindow(frame)
        return True

class SudokuFrame(wx.Frame):

    def __init__(self, title, pos, size):
        wx.Frame.__init__(self, None, -1, title, pos, size, style =    
                          wx.DEFAULT_FRAME_STYLE
                          ^ (wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
        self.title = title
        self.initStatusBar()
        self.createMenuBar()
        self.grid = SudokuGrid(self)
        
        panel = wx.Panel(self, -1, size = (400,450))        
        buttonSTEP = wx.Button(panel, -1, "Step", pos=(100, 400))                  #define browse button
        self.Bind(wx.EVT_BUTTON, self.OnClickStep, buttonSTEP)
        buttonREFRESH = wx.Button(panel, -1, "Refresh", pos=(200, 400))                 #define browse button
        self.Bind(wx.EVT_BUTTON, self.OnClickRefresh, buttonREFRESH)

        self.owildcard = "All files (*.*)|*.*"  

    def initStatusBar(self):
        """
        Initialize the status bar
        """
        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetFieldsCount(3)
        self.statusbar.SetStatusWidths([-2, -2, -3])
#------------------------------------------------------------------------------------------------------------------------------ 
    def menuData(self):
        """
        Define the menu items in the menus
        Return the list of menu items and their display names
        and their handler
        """
        return [("&File", (
                    ("&New", "New Game", self.OnNew),
                    ("&Open", "Open Original file", self.OnOpen),
                    ("", "", ""),
                    ("&Quit", "Quit", self.OnQuit))), 
                ("&Help", (
                    ("&About..", "About Sudoku", self.OnAbout),))]
#------------------------------------------------------------------------------------------------------------------------------     
    def createMenu(self, menuData):
        """
        Create Menus list in the menuData
        """
        menu = wx.Menu()                                                        #get wx.Menu instance
        for eachItem in menuData:
            if len(eachItem) == 2:
                label = eachItem[0]
                subMenu = self.createMenu(eachItem[1])                          #create the subMenu if it exists(recursively)
                menu.AppendMenu(wx.NewId(), label, subMenu)
            else:
                self.createMenuItem(menu, *eachItem)                            #bind every menu item with their attributes
                                                                                #by calling createMenuItem()
        return menu
#------------------------------------------------------------------------------------------------------------------------------ 
    def createMenuBar(self):
        """
        Create Menu Bar by the return of menuData
        """
        menuBar = wx.MenuBar()                                                  #get wx.MenuBar instance
        for eachMenuData in self.menuData():        
            menuLabel = eachMenuData[0]                                         #get the menu label
            menuItems = eachMenuData[1]                                         #get the menu and its items    
            menuBar.Append(self.createMenu(menuItems), menuLabel)               #get menus from createMenu to build menuBar
        self.SetMenuBar(menuBar)                
#------------------------------------------------------------------------------------------------------------------------------ 
    def createMenuItem(self, menu, label,
                       status, handler, kind = wx.ITEM_NORMAL):
        """
        Create menu items according to the list
        Bind the items with their attributes
        """
        if not label:
            menu.AppendSeparator()                                              #add empty seperator
            return
        menuItem = menu.Append(-1, label, status, kind)                         #add the menu items
        self.Bind(wx.EVT_MENU, handler, menuItem)                               #bind the handler
#------------------------------------------------------------------------------------------------------------------------------ 
    def OnOpen(self, event):
        """
        Opne a file to operate
        """
        dlg = wx.FileDialog(self, "Open Original file...", os.getcwd(),
                           style=wx.OPEN, wildcard=self.owildcard)              #show file dialog to open a file
        if dlg.ShowModal() == wx.ID_OK:
            filename = dlg.GetPath()                                       #get the file name
            self.getFile(filename)                                       #pass the file name to encrypt instance
            self.SetTitle(self.title + ' -- ' + filename)                  #reset title
        dlg.Destroy()
        pass
#------------------------------------------------------------------------------------------------------------------------------         
    def getFile(self, filename = None):
        if not filename:
            wx.MessageBox("No file is opened!",
                          "Warning", wx.OK, self)
        try:
            fn = open(filename, 'r')
            content = fn.read()
        except:
            content = ''
        finally:
            fn.close()
        self.parse(content)
#------------------------------------------------------------------------------------------------------------------------------         
    def parse(self, content):
        if not content:
            wx.MessageBox("File is not correct!",
                          "Warning", wx.OK, self)
        try:
            palace = eval(content)
        except:
            pass
        finally:
            if type(palace) is not tuple:
                wx.MessageBox("File format is not correct!",
                              "Warning", wx.OK, self)
                palace = ''
        if palace:
            self.grid = None
            self.grid = SudokuGrid(self, palace)
#------------------------------------------------------------------------------------------------------------------------------         
    def OnNew(self, event):
        self.grid = None
        self.grid = SudokuGrid(self)
        pass
#------------------------------------------------------------------------------------------------------------------------------             
    def OnQuit(self, event):
        """
        Quit the program
        """
        self.Close()
#------------------------------------------------------------------------------------------------------------------------------          
    def OnAbout(self, event):
        """
        Provide the information of program
        """
        wx.MessageBox("This is a Sudoku Game.", 
                "About Sudoku", wx.OK | wx.ICON_INFORMATION, self)

    def OnClickStep(self, evt):
        self.grid.Step()

    def OnClickRefresh(self, evt):
        self.grid.Refresh()

    def __delete__(self):
        pass        


class SudokuGrid(gridlib.Grid):
    def __init__(self, parent, palace = ()):
        gridlib.Grid.__init__(self, parent, -1, size = (380, 380))
##        self.renderer = PuzzleCellRenderer(self)
##        self.SetDefaultRenderer(self.renderer)
        self.drawGrid()
        if not palace:
            palace = ((4, 1, 2), (2, 1, 5), (7, 1, 7), (1, 2, 4),
                      (3, 2, 5), (2, 2, 6), (8, 2, 7), (8, 3, 0),
                      (9, 3, 3), (6, 3, 5), (4, 3, 7), (7, 4, 0),
                      (1, 4, 2), (2, 4, 7), (9, 4, 8), (1, 6, 0),
                      (8, 6, 1), (5, 6, 6), (3, 6, 7), (7, 6, 8),
                      (5, 7, 3), (6, 7, 4), (4, 7, 8), (7, 8, 2))

##          palace = ((5, 0, 3), (2, 0, 4), (3, 0, 7), (5, 1, 2),
##                      (6, 1, 3), (9, 2, 0), (2, 2, 2), (8, 2, 3),
##                      (4, 2, 4), (7, 3, 2), (6, 3, 5), (6, 4, 0),
##                      (5, 4, 4), (2, 4, 7), (4, 4, 8), (1, 5, 6),
##                      (9, 5, 7), (5, 6, 1), (4, 6, 5), (9, 6, 6),
##                      (7, 7, 0), (2, 7, 3), (3, 8, 2), (9, 8, 4),
##                      (8, 8, 8))
        
        self.definePalace(palace)    
        self.Refresh()
        
        self.Bind(gridlib.EVT_GRID_SELECT_CELL, self.OnSelectCell)

        
    def drawGrid(self):
        """
        Setup the basic grid.
        draw 9*9 grid.
        set label size, lock grid size, setup attribute.
        set block background colour as following:
        000XXX000
        XXX000XXX
        000XXX000
        '0' is white, 'X' is grey.
        """
        self.CreateGrid(9,9)
        self.SetRowLabelSize(20)
        self.SetColLabelSize(20)
        self.DisableDragGridSize()
        
        attr = gridlib.GridCellAttr()
        attr.SetAlignment(wx.ALIGN_CENTRE, wx.ALIGN_CENTRE)
        attr.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD))
        
        for i in range(9):
            self.SetRowSize(i, 40)
            self.SetColSize(i, 40)
            self.SetRowAttr(i, attr)
        self.SetGridLineColour(wx.BLACK)

        mid = (3, 4, 5)
        self.textColorSet = {}
        for i in range(9):
            for j in range(9):
                if ((i in mid) and (j not in mid)) or ((j in mid) and (i not in mid)):
                    self.SetCellBackgroundColour(i, j, (230, 230, 230))
                self.textColorSet[(i, j)] =  wx.BLACK

    def definePalace(self, palace):
        """
        Initialize Npalace.Palace.
        define question in the palace.
        change the colour of init question.
        Set the grids of question 'read only'.
        """
        self.p = Npalace.Palace(3)
        
        self.p.multiDefine(palace)
        for valTuple in palace:
            i = valTuple[1]
            j = valTuple[2]
##            self.SetCellBackgroundColour(i, j, (126, 126, 126))
            self.SetCellTextColour(i, j, wx.BLUE)
            self.textColorSet[(i, j)] = wx.BLUE
##            self.SetReadOnly(i, j)
            
            
        
    def OnSelectCell(self, evt):
        row = self.GetGridCursorRow()
        col = self.GetGridCursorCol()
        print str((row, col))
        value = None
        try:
            value = int(self.GetCellValue(row, col))
        except:
            value = None
        self.p.define(value, row, col)
        self.Refresh()
        print self.p.pri[row][col]
        self.p.printP(self.p.pri)
##        self.SetCellTextColour(row, col, wx.RED)

        evt.Skip()

    def Refresh(self):
        for i in range(9):
            for j in range(9):
                self.SetCellValue(i, j, str(True and self.p.pri[i][j] or ''))                
##                self.SetCellTextColour(i, j, wx.BLACK)
                self.SetCellTextColour(i, j, self.textColorSet[(i, j)])
                
    def Step(self):
        ordi = self.p.step()
        self.p.printP(self.p.res)
        self.Refresh()
        for all in ordi:
            self.SetCellTextColour(all[0], all[1], wx.RED)
 

##class SudokuFrame(wx.Frame):
##    def __init__(self, parent):
##        wx.Frame.__init__(self,parent,-1, "Simple", size = (420,470),
##                              style = wx.DEFAULT_FRAME_STYLE
##                              ^ (wx.RESIZE_BORDER | wx.MAXIMIZE_BOX))
##        
##
##        self.grid = SudokuGrid(self)
##        
##        panel = wx.Panel(self, -1, size = (420,470))        
##        buttonSTEP = wx.Button(panel, -1, "Step", pos=(100, 410))                  #define browse button
##        self.Bind(wx.EVT_BUTTON, self.OnClickStep, buttonSTEP)
##        buttonREFRESH = wx.Button(panel, -1, "Refresh", pos=(200, 410))                 #define browse button
##        self.Bind(wx.EVT_BUTTON, self.OnClickRefresh, buttonREFRESH)
##
##    def OnClickStep(self, evt):
##        self.grid.Step()
##
##    def OnClickRefresh(self, evt):
##        self.grid.Refresh()
##
##    def __delete__(self):
##        pass        
        

if __name__ == '__main__':
##    app = wx.PySimpleApp()
##    frame = SudokuFrame(None) 
##    frame.Show(True) 
##    app.MainLoop()
##    app = None
    app = SudokuApp(False)
    app.MainLoop()

    
